﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
// using System.Windows.Forms;

namespace LexicalAnalysisCs
{
    // call the LexicalAnalysis(cpp version)'s exe to do the analysis
    public class LexicalAnalyzerCs
    {
        public class StrInt : IComparable
        {
            public string mContent;
            public int mEndIndex;

            public StrInt(string mContent, int mEndIndex)
            {
                this.mContent = mContent;
                this.mEndIndex = mEndIndex;
            }

            public int CompareTo(object obj)
            {
                StrInt tmp = (StrInt) obj;
                return this.mContent.CompareTo(tmp.mContent);
            }
        }
        private List<StrInt> mResList;

        public List<StrInt> getResList
        {
            get { return mResList; }
        }

        private void ExecuteLexicalAnalysisCpp(string inFileName, string outFileName)
        {
            // Add a new line to make sure the Cpp exe can be finished.
            StreamWriter sr = new StreamWriter(inFileName, true);
            sr.WriteLine("");
            sr.Close();

            System.Diagnostics.Process exeFile = new Process();
            exeFile.StartInfo.FileName = @"LexicalAnalysisCpp.exe";
            exeFile.StartInfo.Arguments = inFileName + ' ' + outFileName;
            exeFile.StartInfo.CreateNoWindow = true;
            exeFile.StartInfo.UseShellExecute = false;
//            Console.WriteLine(inFileName + ' ' + outFileName);

            try
            {
                exeFile.Start();
                exeFile.WaitForExit();
            } 
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        private void GetWordsList(string inFileName)
        {
            try
            {
                FileStream fs = new FileStream(inFileName, FileMode.Open);
                StreamReader sr = new StreamReader(fs);
                string tmp = "";
                while (tmp != null)
                {
                    tmp = sr.ReadLine();
                    if (tmp != null && !tmp.Equals(""))
                    {
                        string[] x = Regex.Split(tmp, "\\@\\@\\@");
                        // 坑死爹了。。。这里他妈的bug表现的地方太上层了。。。遇到老大一个问题。。。还好解决掉了。。。
                        if (x.Length > 1)
                        {
                            mResList.Add(new StrInt(x[1], int.Parse(x[0])));
                        } 
                        else if (x.Length == 1) // !!!!!!!!!!!!!!!!!!!!!!!!!
                        {
                            mResList[mResList.Count - 1].mContent += "\n" + x[0];
                        }
                        else // if (x.Length == 0) // !!!!!!!!!!!!!!!!!!!!!!!!!
                        {
                            mResList[mResList.Count - 1].mContent += "\n";
                        }
                    }
                }
                sr.Close();
                fs.Close();
           }
            catch (Exception ex)
            {
//                MessageBox.Show(ex.Message);
                Console.WriteLine(ex.Message);
            }

        }

        public LexicalAnalyzerCs(string inFileName, string outFileName)
        {
            ExecuteLexicalAnalysisCpp(inFileName, outFileName);
            mResList = new List<StrInt>();
            GetWordsList(outFileName);
        }

        public List<StrInt> GetIncludeFileNames(bool doEraseInclude)
        {
            List<StrInt> resList = new List<StrInt>();

            for (int i = mResList.Count - 1; i >= 0; i--)
            {
                if (mResList[i].mContent.Equals("#") && mResList[i + 1].mContent.Equals("include"))
                {
                    if (mResList[i + 2].mContent.Equals("<"))
                    {
                        resList.Add(mResList[i + 3]);
                        if (doEraseInclude)
                        {
                            for (int j = 4; j >= 0; j--)
                            {
                                mResList.RemoveAt(i + j);
                            }
                        }
                    }
                    else
                    {
                        resList.Add(new StrInt(
                            mResList[i + 2].mContent.Substring(1, mResList[i + 2].mContent.Length - 2),
                            mResList[i + 2].mEndIndex - 1
                            ));
                        if (doEraseInclude)
                        {
                            for (int j = 2; j >= 0; j--)
                            {
                                mResList.RemoveAt(i + j);
                            }
                        }
                    }
                }
            }

            resList.Sort();
            return resList;
        }

        public List<StrInt> GetNamespaceName(bool doEraseNamespace)
        {
            List<StrInt> resList = new List<StrInt>();

            for (int i = mResList.Count - 1; i >= 0; i--)
            {
                if (mResList[i].mContent.Equals("using") && mResList[i + 1].mContent.Equals("namespace"))
                {
                    resList.Add(mResList[i + 2]);
                    if (doEraseNamespace)
                    {
                        for (int j = 3; j >= 0; j--)
                        {
                            mResList.RemoveAt(i + j);
                        }
                    }
                }
            }

            resList.Sort();
            return resList;
        }

        public void GetWordsSymbolsList(ref List<StrInt> wordsList, ref List<StrInt> symbolsList)
        {
            foreach (var si in mResList)
            {
                char tmp = si.mContent[0];
                if ((tmp >= 'A' && tmp <= 'Z')
                  || (tmp >= 'a' && tmp <= 'z')
                  || (tmp >= '0' && tmp <= '9')
                  || tmp == '\"' || tmp == '.')
                {
                    wordsList.Add(si);
                }
                else
                {
                    symbolsList.Add(si);
                }
            }
        }
        
    }
}
